package com.common.excel;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.common.vo.DateUtils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.NumberUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @author johnny
 * @create 2019-10-30 下午4:51
 * 监听类，可以自定义
 **/
@Slf4j
@Getter
public abstract class ExcelListener<T> extends AnalysisEventListener<T> {

    public static List<Object> datas = new ArrayList<>();

    public static Map<Integer, List<ExcelValueCheckResp.ErrorInfoResp>> checkResps = new HashMap<>();

    public static ExcelValueCheckResp excelValueCheckResp = new ExcelValueCheckResp();


    public static void clean() {
        checkResps = new HashMap<>();
        excelValueCheckResp = new ExcelValueCheckResp();
        datas = new ArrayList<>();
    }

    StringBuilder errorMsgBuilder = new StringBuilder();

    public static ExcelValueCheckResp excelValueCheckResp() {
        return excelValueCheckResp;
    }

    public static List<Object> getDatas() {
        return datas;
    }


    @Override
    public void invoke(T object, AnalysisContext analysisContext) {
        boolean emptyFlag;
        //校验 excel null
        emptyFlag = filterExcelNullData(object);
        if (emptyFlag) {
            return;
        }

        //将errorMsgBuilder 清空
        Field[] fieldArr = object.getClass().getDeclaredFields();
        errorMsgBuilder.delete(0, errorMsgBuilder.length());
        for (Field field : fieldArr) {
            field.setAccessible(true);
            //校验空值
            if (field.isAnnotationPresent(ExcelValueNotNull.class)) {
                ExcelValueNotNull excelValue = field.getAnnotation(ExcelValueNotNull.class);
                try {
                    if (field.get(object) == null) {
                        analysisContext.getCurrentRowNum();
                        errorMsgBuilder.append(excelValue.columnName() + ":" + excelValue.message() + " ");
                    }
                } catch (IllegalAccessException e) {
                    log.error("【获取属性值异常 {}】", e.getMessage());
                }
            }
            //类型检查注解
            if (field.isAnnotationPresent(ExcelValueTypeCheck.class)) {
                ExcelValueTypeCheck excelValueTypeCheck = field.getAnnotation(ExcelValueTypeCheck.class);
                try {
                    Object value = field.get(object);
                    if (excelValueTypeCheck.typeClass() == Date.class) {
                        if (field.isAnnotationPresent(ExcelValueNotNull.class)) {
                            if (!(value instanceof Date)) {
                                log.error("【excel 参数类型不匹配: {} ,需要日期类型 格式: {} 】", value, excelValueTypeCheck.dateFormate());
                                putErrorInfo((analysisContext.getCurrentRowNum() + 1), new ExcelValueCheckResp.ErrorInfoResp(excelValueTypeCheck.columnName() + "：excel参数 " + value + " 类型不匹配 " + excelValueTypeCheck.message()),
                                        checkResps);
                                excelValueCheckResp.setErrorInfoRespMap(checkResps);
                                return;
                            }
                        }
                    } else {
                        try {
                            NumberUtils.parseNumber(String.valueOf(value), excelValueTypeCheck.typeClass());
                        } catch (IllegalArgumentException e) {
                            log.error("【excel 参数类型不匹配: {} ,需要 {} 类型】", value, excelValueTypeCheck.typeClass());
                            putErrorInfo((analysisContext.getCurrentRowNum() + 1), new ExcelValueCheckResp.ErrorInfoResp(excelValueTypeCheck.columnName() + "：excel参数 " + value + " 类型不匹配 " + excelValueTypeCheck.message()),
                                    checkResps);
                            excelValueCheckResp.setErrorInfoRespMap(checkResps);
                            return;
                        }
                    }
                } catch (IllegalAccessException e) {
                    log.error("【获取属性值异常 {}】", e.getMessage());
                }
            }
        }
        if (!StringUtils.isEmpty(errorMsgBuilder.toString())) {
            putErrorInfo((analysisContext.getCurrentRowNum() + 1), new ExcelValueCheckResp.ErrorInfoResp(errorMsgBuilder.toString()),
                    checkResps);
        } else {
            //前置处理
            boolean pass = preProcess(object, (analysisContext.getCurrentRowNum() + 1), checkResps);
            if (pass) {
                //可重写 具体业务
                doSomething(object);
                postProcess(object);
                excelValueCheckResp.setSucNumber(excelValueCheckResp.getSucNumber() + 1);
            } else {
                excelValueCheckResp.setFailNumber(excelValueCheckResp.getFailNumber() + 1);
            }
        }
        excelValueCheckResp.setErrorInfoRespMap(checkResps);
    }

    private boolean filterExcelNullData(T object) {
        boolean emptyFlag = true;
        //判断是否读取了 全部未null的数据
        Field[] fieldArr = object.getClass().getDeclaredFields();
        for (Field field : fieldArr) {
            field.setAccessible(true);
            try {
                if (field.get(object) != null) {
                    emptyFlag = false;
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        if (emptyFlag == true) {
            log.info("【读取到Excel Null数据】");
            return true;
        } else {
            return false;
        }
    }

    /**
     * 具有业务逻辑
     *
     * @param t : excel 对象
     */
    protected void doSomething(T t) {
        datas.add(t);
    }

    /**
     * 如果需要校验 需要重写
     * <p>
     * 主要是 前置处理 检查数据是否满足规则，如是否满足字典 等等。。
     *
     * @param t            : excel对象
     * @param rowNumber    : 行数
     * @param checkRespMap : 校验结果对象
     * @return : 是否通过 通过返回true
     */
    protected boolean preProcess(T t, Integer rowNumber, Map<Integer, List<ExcelValueCheckResp.ErrorInfoResp>> checkRespMap) {
        return true;
    }


    /**
     * 后置处理
     *
     * @param t
     */
    protected void postProcess(T t) {

    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    }

    public static void putErrorInfo(Integer rowNumber, ExcelValueCheckResp.ErrorInfoResp errorInfoResp, Map<Integer, List<ExcelValueCheckResp.ErrorInfoResp>> errorMap) {
        if (!StringUtils.isEmpty(errorMap)) {
            if (!StringUtils.isEmpty(errorMap.get(rowNumber))) {
                errorMap.get(rowNumber).add(errorInfoResp);
            } else {
                List<ExcelValueCheckResp.ErrorInfoResp> list = new ArrayList<>();
                list.add(errorInfoResp);
                errorMap.put(rowNumber, list);
            }
        }
    }

}